<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  

  
  <title>IO编程和NIO编程简介 | 海晨忆的博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  
  
  
  <meta name="description" content="&amp;emsp;&amp;emsp;传统的同步阻塞I/O通讯模型，导致的结果就是只要有一方处理数据缓慢，都会影响另外一方的处理性能。按照故障设计原则，一方的处理出现问题，不应该影响到另外一方才对。但是，在同步阻塞的模式下面，这样的情况是无法避免的，很难通过业务层去解决。既然同步无法避免，为了避免就产生了异步。Netty框架就一个完全异步非阻塞的I/O通讯方式">
<meta property="og:type" content="article">
<meta property="og:title" content="IO编程和NIO编程简介">
<meta property="og:url" content="https://haichenyi.com/2018/02/07/IO编程和NIO编程简介/index.html">
<meta property="og:site_name" content="海晨忆的博客">
<meta property="og:description" content="&amp;emsp;&amp;emsp;传统的同步阻塞I/O通讯模型，导致的结果就是只要有一方处理数据缓慢，都会影响另外一方的处理性能。按照故障设计原则，一方的处理出现问题，不应该影响到另外一方才对。但是，在同步阻塞的模式下面，这样的情况是无法避免的，很难通过业务层去解决。既然同步无法避免，为了避免就产生了异步。Netty框架就一个完全异步非阻塞的I/O通讯方式">
<meta property="og:locale" content="zh-Hans">
<meta property="og:updated_time" content="2018-02-22T13:08:36.720Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="IO编程和NIO编程简介">
<meta name="twitter:description" content="&amp;emsp;&amp;emsp;传统的同步阻塞I/O通讯模型，导致的结果就是只要有一方处理数据缓慢，都会影响另外一方的处理性能。按照故障设计原则，一方的处理出现问题，不应该影响到另外一方才对。但是，在同步阻塞的模式下面，这样的情况是无法避免的，很难通过业务层去解决。既然同步无法避免，为了避免就产生了异步。Netty框架就一个完全异步非阻塞的I/O通讯方式">
  
    <link rel="alternate" href="/atom.xml" title="海晨忆的博客" type="application/atom+xml">
  
  
    <link rel="icon" href="/uploads/artistic_image/head.jpg">
  
  
    <link href="//fonts.googleapis.com/css?family=Source+Code+Pro" rel="stylesheet" type="text/css">
  
  <link rel="stylesheet" href="/css/style.css">
  <link rel="stylesheet" href="/css/highlight.css">
  <script>
  let antiquityStorage = window.sessionStorage.getItem('antiquitySessionStorage');
  if (antiquityStorage == '' || antiquityStorage == null) {
    var antiquityLoader = '<div id="loaderbox"><div class="loader"><div class="load-roll"><div class="load-top"></div><div class="load-right"></div><div class="load-bottom"></div></div></div></div>';
    document.write(antiquityLoader);
    document.body.style.overflow = 'hidden'
  }
  </script>
</head>

<body>
  <div id="fullpage" class="mobile-nav-right">
    
      <div id="wrapper" style="background-image: url(/uploads/artistic_image/bg.jpg)" title="背景图片来自网络">
    
    
      <header id="header">
  <div id="nav-toggle" class="nav-toggle"></div>
  <div class="head-box global-width">
    <nav class="nav-box nav-right">
      
        <a class="nav-item" href="/" title
        
        >首页</a>
      
        <a class="nav-item" href="/archives" title
        
        >归档</a>
      
        <a class="nav-item" href="/about" title
        
        >简历</a>
      
    </nav>
  </div>
</header>
      <div id="middlecontent" title class="global-width sidebar-left">
        <section id="main"><article id="post-IO编程和NIO编程简介" class="article global-container article-type-post" itemscope itemprop="blogPost">
  
    <header class="article-header">
      
  
    <h1 class="article-title" itemprop="name">
      IO编程和NIO编程简介
    </h1>
  

    </header>
  
  <div class="article-meta">
    <a href="/2018/02/07/IO编程和NIO编程简介/" class="article-date">
  <time datetime="2018-02-07T12:49:47.000Z" itemprop="datePublished">2018-02-07</time>
</a>
    
  <div class="article-category">
    <a class="article-category-link" href="/categories/Android-Socket/">Android -Socket</a>
  </div>

    
  </div>
  
    <span id="busuanzi_container_page_pv">
      本文总阅读量<span id="busuanzi_value_page_pv"></span>次
    </span>
  

  <div class="article-inner">
    
    <div class="article-content article-content-cloud doorframe mac" itemprop="articleBody">
      
        <p>&emsp;&emsp;传统的同步阻塞I/O通讯模型，导致的结果就是只要有一方处理数据缓慢，都会影响另外一方的处理性能。按照故障设计原则，一方的处理出现问题，不应该影响到另外一方才对。但是，在同步阻塞的模式下面，这样的情况是无法避免的，很难通过业务层去解决。既然同步无法避免，为了避免就产生了异步。Netty框架就一个完全异步非阻塞的I/O通讯方式<br><a id="more"></a></p>
<h2 id="同步阻塞式I-O编程"><a href="#同步阻塞式I-O编程" class="headerlink" title="同步阻塞式I/O编程"></a>同步阻塞式I/O编程</h2><p>&emsp;&emsp;简单的来说，传统同步阻塞的I/O通讯模式，服务器端处理的方式是，每当有一个新用户接入的时候，就new一个新的线程，一个线程只能处理一个客户端的连接，在高性能方面，并发高的情景下无法满足。伪代码如下：</p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">import java.io.IOException;</span><br><span class="line">import java.net.ServerSocket;</span><br><span class="line">import java.net.Socket;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * @author 海晨忆</span><br><span class="line"> * @date 2018/2/9</span><br><span class="line"> * @desc</span><br><span class="line"> */</span><br><span class="line">public class SocketServer &#123;</span><br><span class="line">  private int port = 8080;</span><br><span class="line">  private Socket socket = null;</span><br><span class="line"></span><br><span class="line">  public SocketServer(int port) &#123;</span><br><span class="line">    this.port = port;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public void connect() &#123;</span><br><span class="line">    ServerSocket server = null;</span><br><span class="line">    try &#123;</span><br><span class="line">      server = new ServerSocket(port);</span><br><span class="line">      while (true) &#123;</span><br><span class="line">        socket = server.accept();</span><br><span class="line">        new Thread(new Runnable() &#123;</span><br><span class="line">          @Override</span><br><span class="line">          public void run() &#123;</span><br><span class="line">            new TimerServerHandler(socket).run();</span><br><span class="line">          &#125;</span><br><span class="line">        &#125;).start();</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125; finally &#123;</span><br><span class="line">      //释放资源</span><br><span class="line">      if (server != null) &#123;</span><br><span class="line">        try &#123;</span><br><span class="line">          server.close();</span><br><span class="line">        &#125; catch (IOException e) &#123;</span><br><span class="line">          e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">        server = null;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">import java.io.BufferedReader;</span><br><span class="line">import java.io.IOException;</span><br><span class="line">import java.io.InputStreamReader;</span><br><span class="line">import java.io.PrintWriter;</span><br><span class="line">import java.net.Socket;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * @author 海晨忆</span><br><span class="line"> * @date 2018/2/9</span><br><span class="line"> * @desc</span><br><span class="line"> */</span><br><span class="line">public class TimerServerHandler implements Runnable &#123;</span><br><span class="line">  private Socket socket;</span><br><span class="line"></span><br><span class="line">  public TimerServerHandler(Socket socket) &#123;</span><br><span class="line">    this.socket = socket;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  @Override</span><br><span class="line">  public void run() &#123;</span><br><span class="line">    BufferedReader in = null;</span><br><span class="line">    PrintWriter out = null;</span><br><span class="line">    try &#123;</span><br><span class="line">      in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));</span><br><span class="line">      out = new PrintWriter(this.socket.getOutputStream(), true);</span><br><span class="line">      String currentTime = null;</span><br><span class="line">      String body = null;</span><br><span class="line">      while (true) &#123;</span><br><span class="line">        body = in.readLine();</span><br><span class="line">        if (body == null)</span><br><span class="line">          break;</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">      //释放in，out，socket资源</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;上面这个就是最原始的服务端IO的代码，这里我就给出的是最简化的，当有新的客户端接入的时候，服务端是怎么处理线程的，可以看出，每当有新的客户端接入的时候，总是回新创建一个线程去服务这个新的客户端</p>
<h2 id="伪异步式编程"><a href="#伪异步式编程" class="headerlink" title="伪异步式编程"></a>伪异步式编程</h2><p>&emsp;&emsp;后来慢慢演化出一个版本“伪异步”模型，新增加一个线程池或者消息队列，满足一个线程或者多个线程满足N个客户端，通过线程池可以灵活的调用线程资源。通过设置线程池的最大值，防止海量并发接入造成的线程耗尽，它的底层实现依然是同步阻塞模型，伪代码如下：<br><br><div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">import com.example.zwang.mysocket.server.TimerServerHandler;</span><br><span class="line"></span><br><span class="line">import java.io.IOException;</span><br><span class="line">import java.net.ServerSocket;</span><br><span class="line">import java.net.Socket;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * @author 海晨忆</span><br><span class="line"> * @date 2018/2/9</span><br><span class="line"> * @desc</span><br><span class="line"> */</span><br><span class="line">public class SocketServer &#123;</span><br><span class="line">  private int port = 8080;</span><br><span class="line">  private Socket socket = null;</span><br><span class="line"></span><br><span class="line">  public SocketServer(int port) &#123;</span><br><span class="line">    this.port = port;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  private void connect() &#123;</span><br><span class="line">    ServerSocket server = null;</span><br><span class="line">    try &#123;</span><br><span class="line">      server = new ServerSocket(port);</span><br><span class="line">      TimeServerHandlerExecutePool executePool = new TimeServerHandlerExecutePool(50, 1000);</span><br><span class="line">      while (true) &#123;</span><br><span class="line">        socket = server.accept();</span><br><span class="line">        executePool.execute(new TimerServerHandler(socket));</span><br><span class="line">      &#125;</span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      e.printStackTrace();</span><br><span class="line">    &#125;finally &#123;</span><br><span class="line">      //释放资源</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div></p>
<div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">import java.util.concurrent.ArrayBlockingQueue;</span><br><span class="line">import java.util.concurrent.ExecutorService;</span><br><span class="line">import java.util.concurrent.ThreadPoolExecutor;</span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * @author 海晨忆</span><br><span class="line"> * @date 2018/2/9</span><br><span class="line"> * @desc</span><br><span class="line"> */</span><br><span class="line">public class TimeServerHandlerExecutePool &#123;</span><br><span class="line">  private ExecutorService executor;</span><br><span class="line"></span><br><span class="line">  public TimeServerHandlerExecutePool(int maxPoolSize, int queueSize) &#123;</span><br><span class="line">    executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(), maxPoolSize,</span><br><span class="line">        120L, TimeUnit.SECONDS, new ArrayBlockingQueue&lt;Runnable&gt;(queueSize));</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  public void execute(Runnable task) &#123;</span><br><span class="line">    executor.execute(task);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></div>
<p>&emsp;&emsp;“伪异步”的代码和传统同步的唯一区别就是在于，首先先创建了一个时间服务处理类的线程池，当有新的客户端接入的时候，先将socket请求封装成task，然后调用线程池的execute方法执行，从而避免了每一个新请求创建一个新线程。由于线程池和消息队列都是有限的，因此，无论客户端的并发量多大，它都不会导致线程个数过于大，而造成的内存溢出。相对于传统的同步阻塞，是一种改良。<br></p>
<p>&emsp;&emsp;但是他没有从更本上解决同步的问题，伪异步的问题在于，他还是有一方处理出现问题还是会影响到另一方。因为：</p>
<p>&emsp;&emsp;当对socket的输入流进行读取操作的时候，它会一直阻塞直到一下三种方式发生：  </p>
<ol>
<li><p>有数据可读  </p>
</li>
<li><p>可读数据已经读取完   </p>
</li>
<li><p>发生空指针或者I/O异常。  </p>
</li>
</ol>
<p>这意味者，当读取inputstream方处理速度缓慢(不管是什么原因造成的速度缓慢)，另一方会一直同步阻塞，直到这一方把数据处理完.</p>
<p>&emsp;&emsp;当调用outputstream的write方法写输出流的时候，它将会被阻塞，直到所有要发送的字节全部写入完毕，或者发生异常。学过TCP/IP相关知识的人都直到，当消息的接收方处理消息缓慢，不能及时的从TCP缓冲区读取数据，这将会导致发送方的TCP缓冲区的size一直减少，直到0.缓冲区为0，那么发消息的一方将无法将消息写入缓冲区，直到缓冲区的size大于0<br></p>
<p>&emsp;&emsp;通过以上。我们了解到读和写的操作都是同步阻塞的，阻塞的时间取决于对方的I/O线程的处理速度和网络I/O的传送速度。从本质上面看，我们无法保证对方的处理速度和网络传送速度。如果，我们的程序依靠与对方的处理速度，那么，他的可靠性将会非常差。</p>
<h2 id="NIO编程"><a href="#NIO编程" class="headerlink" title="NIO编程"></a>NIO编程</h2><p>&emsp;&emsp;官方叫法new I/O，也就是新的IO编程，更多的人喜欢称它为：Non-block IO即非阻塞IO。</p>
<p>&emsp;&emsp;与Socket和serverSocket类对应，NIO提供了SocketChannel和ServerSocketChannel两种不同的套接字通道实现，这两种都支持阻塞式编程和非阻塞式编程。开发人员可以根据自己的需求选择合适的编程模式。一般低负载，低并发的应用程序选择同步阻塞的方式以降低编程的复杂度。高负载，高并发的不用想了，非阻塞就是为了解决这个问题的</p>
<ol>
<li>缓冲区Buffer</li>
</ol>
<p>&emsp;&emsp;Buffer是一个对象，它包含一些写入或者读出的数据。再NIO中加入buffer对象，体现了新库和旧库的一个重要区别。在面向流的io中，可以直接把数据读取或者写入到stream对象中。在NIO库中，所有数据操作都是通过缓冲区处理的。</p>
<p>&emsp;&emsp;缓冲区实质上是一个数组，通常是一个字节数组（ByteBuffer），基本数据类型除了boolean没有，其他都有，如ShortBuffer,CharBuffer等等</p>
<ol>
<li>通道Channel</li>
</ol>
<p>&emsp;&emsp;Channel是一个通道，双向通道，网络数据都是通过Channel读取，写入的。是的，没错，Channel它既可以进行读操作，也可以进行写操作。而流只能是一个方向。只能读操作或者只能写操作，而channel是全双工，读写可以同时进行。channel可以分为两大类：网络读写的SelectableChannel和文件操作的FileChannel。我们前面提到的SocketChannel和ServerSocketChannel都是SelectableChannel的子类。</p>
<ol>
<li>多路复用器Selector</li>
</ol>
<p>&emsp;&emsp;selector多路复用器，他是java NIO编程的基础，熟练的掌握selector对于NIO编程至关重要。多路复用器提供选择已经就绪的任务的能力。简单的讲就是他会不断的轮询注册的channel，如果一个Channel发生了读写操作，这个Chnnel就会处于就绪状态，会被selector轮询出来，通过SelectorKey获取就绪Channel集合，进行后续的IO操作。一个selector对应多个Channel<br></p>
<p>&emsp;&emsp;由于原生NIO编码比较麻烦和复杂，我这里就给出了思路的伪代码。下一篇我们将用NIO中的Netty框架实现Socket通信，编码简单，一行代码解决烦人粘包、拆包问题。<br><div class="highlight-box"autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" contenteditable="true"data-rel="PLAIN"><figure class="iseeu highlight /plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br></pre></td><td class="code"><pre><span class="line">/**</span><br><span class="line">   * 服务端nio过程的伪代码</span><br><span class="line">   *</span><br><span class="line">   * @param port 端口号</span><br><span class="line">   * @throws IOException IOException</span><br><span class="line">   */</span><br><span class="line">  private void init(int port) throws IOException &#123;</span><br><span class="line">    //第一步：打开ServerSocketChannel，用于监听客户端连接，它是所有客户端连接的父管道</span><br><span class="line">    ServerSocketChannel socketChannel = ServerSocketChannel.open();</span><br><span class="line">    //第二步：监听绑定端口，设置连接模式为非阻塞模式，</span><br><span class="line">    socketChannel.socket().bind(new InetSocketAddress(InetAddress.getByName(&quot;IP&quot;), port));</span><br><span class="line">    socketChannel.configureBlocking(false);</span><br><span class="line">    //第三步：创建Reactor线程，创建多路复用器，并启动线程。</span><br><span class="line">    Selector selector = Selector.open();</span><br><span class="line">    new Thread().start();</span><br><span class="line">    //第四步：将ServerSocketChannel注册到Reactor线程的多路复用器上，监听accept事件</span><br><span class="line">    SelectionKey key = socketChannel.register(selector, SelectionKey.OP_ACCEPT/*,ioHandler*/);</span><br><span class="line">    //第五步：多路复用器在线程run方法的无线循环体内轮询准备就绪的key</span><br><span class="line">    int num = selector.select();</span><br><span class="line">    Set&lt;SelectionKey&gt; selectionKeys = selector.selectedKeys();</span><br><span class="line">    Iterator&lt;SelectionKey&gt; it = selectionKeys.iterator();</span><br><span class="line">    while (it.hasNext()) &#123;</span><br><span class="line">      SelectionKey next = it.next();</span><br><span class="line">      //deal with io event...</span><br><span class="line">    &#125;</span><br><span class="line">    //第六步：多路复用器检测到有新客户端接入，处理新的接入请求，完成TCP三次握手，建立物理链路</span><br><span class="line">    SocketChannel channel = socketChannel.accept();</span><br><span class="line">    //第七步：设置客户端为非阻塞模式</span><br><span class="line">    channel.configureBlocking(false);</span><br><span class="line">    channel.socket().setReuseAddress(true);</span><br><span class="line">    //第八步：将新接入的客户端注册到reactor线程的多路复用器上，监听读操作，读取客户端发送的消息</span><br><span class="line">    SelectionKey key1 = socketChannel.register(selector, SelectionKey.OP_ACCEPT/*,ioHandler*/);</span><br><span class="line">    //第九步：异步读取客户端消息到缓冲区，</span><br><span class="line">    /*int readNumber = channel.read(&quot;receivebuff&quot;);*/</span><br><span class="line">    //第十步：对byteBuffer进行编解码，如果有半包信息指针reset，继续读取到后续的报文，将解码成功消息封装成task，投递到业务线程池，进行业务逻辑编排</span><br><span class="line">    Object massage = null;</span><br><span class="line">    while (buff.hasRemain()) &#123;</span><br><span class="line">      buff.mark();</span><br><span class="line">      Object massage1 = decode(btyeBuffer);</span><br><span class="line">      if (massage1 == null) &#123;</span><br><span class="line">        byteBuffer.reset();</span><br><span class="line">        break;</span><br><span class="line">      &#125;</span><br><span class="line">      massageList.add(massage1);</span><br><span class="line">    &#125;</span><br><span class="line">    if (!byteBuffer.hasRemain()) &#123;</span><br><span class="line">      byteBuffer.clean();</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">      byteBuffer.compact();</span><br><span class="line">    &#125;</span><br><span class="line">    if (massageList != null &amp;&amp; !massageList.isEmpty()) &#123;</span><br><span class="line">      for (Object massage3 : massageList)&#123;</span><br><span class="line">        handlerTask(massage3);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    //第十一步：将POJO对象encode成ByteBuff，调用SocketChannel的异步write接口，将异步消息发送到客户端</span><br><span class="line">    socketChannel.write(buffer);</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure></div></p>

      
    </div>
    
      <footer class="article-footer">
        完
      </footer>
    
  </div>
  
    
<nav id="article-nav">
  <div class="article-nav-block">
    
      <a href="/2018/02/08/Netty的简单使用，实现socket通讯/" id="article-nav-newer" class="article-nav-link-wrap">
        <strong class="article-nav-caption"></strong>
        <div class="article-nav-title">
          
            Netty的简单使用，实现socket通讯
          
        </div>
      </a>
    
  </div>
  <div class="article-nav-block">
    
  </div>
</nav>

    
  
  
</article>
</section>
        <aside id="sidebar">
  
    <div class="widget-box">
  <div class="avatar-box avatar-item">
    <img class="avatar" src="/uploads/artistic_image/head.jpg" title="头像来自网络"></img>
    <h3 class="avatar-name">
      
        海晨忆
      
    </h3>
    <p class="avatar-slogan">
      先谋生，再谋爱。人间值得，未来可期。
    </p>
  </div>
</div>


  
    
  <div class="widget-box">
    <h3 class="widget-title">分类</h3>
    <div class="widget">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/Android-Socket/">Android -Socket</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-加密算法/">Android -加密算法</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-常用功能/">Android -常用功能</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-框架/">Android -框架</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-源码解析/">Android -源码解析</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-自定义view/">Android -自定义view</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Android-设计模式/">Android -设计模式</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/JAVA-并发/">JAVA -并发</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Java-SpringBoot/">Java -SpringBoot</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/Tomcat/">Tomcat</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/kotlin/">kotlin</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-JDBC/">数据库 -JDBC</a></li><li class="category-list-item"><a class="category-list-link" href="/categories/数据库-MySQL/">数据库 -MySQL</a></li></ul>
    </div>
  </div>


  
    

  
    
  
    
  <div class="widget-box">
    <h3 class="widget-title">归档</h3>
    <div class="widget">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2021/07/">July 2021</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/11/">November 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/10/">October 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/09/">September 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/08/">August 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/07/">July 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2019/06/">June 2019</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/10/">October 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/05/">May 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/03/">March 2018</a></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2018/02/">February 2018</a></li></ul>
    </div>
  </div>

  
    
  <div class="widget-box">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget">
      <ul>
        
          <li>
            <a href="/2021/07/27/JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁/">JAVA—公平锁，非公平锁，悲观锁，乐观锁，死锁</a>
          </li>
        
          <li>
            <a href="/2021/07/19/JAVA—线程同步器AQS/">JAVA—线程同步器AQS</a>
          </li>
        
          <li>
            <a href="/2021/07/07/Android模拟点击/">Android模拟点击</a>
          </li>
        
          <li>
            <a href="/2019/11/27/SpringBoot系列-消息-RabbitMQ-（二十）/">SpringBoot系列-消息(RabbitMQ)（二十）</a>
          </li>
        
          <li>
            <a href="/2019/11/13/SpringBoot系列-Docker（十九）/">SpringBoot系列-Docker（十九）</a>
          </li>
        
      </ul>
    </div>
  </div>

  
      <div class="widget-box">
    <h3 class="widget-title">友情链接</h3>
    <div class="widget">
      
        <a class="hrf" style="display: block;" href="https://github.com/haichenyi" title target='_blank'
        >Github</a>
      
        <a class="hrf" style="display: block;" href="https://www.jianshu.com/u/6077ee440c37" title target='_blank'
        >简书</a>
      
        <a class="hrf" style="display: block;" href="https://blog.csdn.net/qq_27634797" title target='_blank'
        >CSDN</a>
      
    </div>
  </div>

  
</aside>
      </div>
      <footer id="footer">
  <div class="foot-box footers global-width">
    &copy;2017-2021 海晨忆 &nbsp;&nbsp;
    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span id="busuanzi_container_site_pv">阁下是第<span id="busuanzi_value_site_pv"></span>个访客</span>
  </div>
</footer>
      <script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script>
if (!window.jQuery) {
var script = document.createElement('script');
script.src = "/js/jquery-2.0.3.min.js";
document.body.write(script);
}
</script>

  <link rel="stylesheet" href="/fancybox/jquery.fancybox.css">
  <script src="/fancybox/jquery.fancybox.pack.js"></script>


<script src="/js/script.js"></script>



    </div>
    <nav id="mobile-nav" class="mobile-nav-box">
  <div class="mobile-nav-img mobile-nav-top"></div>
  
    <a href="/" class="mobile-nav-link">首页</a>
  
    <a href="/archives" class="mobile-nav-link">归档</a>
  
    <a href="/about" class="mobile-nav-link">简历</a>
  
  <div class="mobile-nav-img  mobile-nav-bottom"></div>
</nav>    
  </div>
</body>
</html>